package com.csx.base;

import com.xxl.job.core.util.DateUtil;
import com.yh.csx.bsf.bigdata.BigDataSource;
import com.yh.csx.bsf.core.base.Callable;
import com.yh.csx.bsf.core.base.Ref;
import com.yh.csx.bsf.core.db.DbHelper;
import com.yh.csx.bsf.core.util.ConvertUtils;
import com.yh.csx.bsf.core.util.FileUtils;
import com.yh.csx.bsf.core.util.LogUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.var;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.Assert;

import java.io.File;
import java.util.*;
import java.util.Map.Entry;

/**
 * Tidb 适配器
 * 
 * @author Robin.Wang
 * @date 2020-05-29
 *
 */
public class TidbAdapter {
	@Data
	@AllArgsConstructor
	protected static class Command{
		private String table;
		private String cmd;
	}

	protected StragtegyProvider stragtegyProvider  = com.csx.Context.StragtegyProvider;

	/**
	 * 判断库是否存在
	 *
	 * @return boolean
	 * @throws Exception
	 */
	protected boolean createDatabase(String database) {
		Assert.hasText(database, "table can't be null");
		String sql = "create database if not exists " + database;
		return executeUpdate(sql);
	}

	/**
	 * 判断表是否存在
	 * 
	 * @param table 库名.表名
	 * @return boolean
	 * @throws Exception
	 */
	public boolean existsTable(String table) {
		String sql = "select table_name from information_schema.TABLES where table_schema='"+stragtegyProvider.parseDb(table)+"' and table_name='"+stragtegyProvider.parseTable(table)+"' limit 0,1";
		return query(sql).size()>0;
	}

	public List<String> existsTable(List<String> tables) {
		var rs = new ArrayList<String>();
		StringBuilder sb = new StringBuilder("where 1=1 ");
		for(var table:tables){
			sb.append(" or (table_schema='"+stragtegyProvider.parseDb(table)+"' and table_name='"+stragtegyProvider.parseTable(table)+"')");
		}
		String sql = "select table_schema,table_name from information_schema.TABLES "+sb.toString();
		var data = query(sql);
		for(var d:data){
			rs.add(stragtegyProvider.fullName(ConvertUtils.convert(d.get("table_schema".toUpperCase()),String.class),ConvertUtils.convert(d.get("table_name".toUpperCase()),String.class)));
		}
		return rs;
	}



	/**
	 * 重命名表名
	 * 
	 * @param oldName 原表名
	 * @param newName 新表名
	 * @return boolean
	 * @throws Exception
	 */
	public boolean renameTable(String oldName, String newName) {
		String sql = "rename table " + oldName + " to " + newName;
		return executeUpdate(sql);
	}


	public List<String> getAllFullNameTables(){
		var result = new ArrayList<String>();
		List<Map<String, Object>> rs = query("select distinct table_schema,table_name from information_schema.columns");
		for(var r:rs)
		{
			var db = ConvertUtils.convert(r.get("table_schema".toUpperCase()),String.class);
			var table = ConvertUtils.convert(r.get("table_name".toUpperCase()),String.class);
			result.add(stragtegyProvider.fullName(db,table));
		}
		return result;
	}


	public Map<String,Date> selectUpdate(String tableName,List<String> ids){
		var sql = "select id,update_time from "+tableName+" where id in ('"+ StringUtils.join(ids,"','")+"') ";
		var rs = new HashMap<String,Date>();
		for(var o:query(sql)){
			rs.put(ConvertUtils.convert(o.get("id"),String.class),ConvertUtils.convert(o.get("update_time"),Date.class));
		}
		return rs;
	}


	public Long selectCount(String tableName,Date date) {
		String sql="select count(*) as count from "+tableName;
		if(!(date==null)) {
			sql = "select count(*) as count from "+tableName+" where create_time<= '" + DateUtil.formatDateTime(date) + "'";
		}
		return ConvertUtils.convert( query2(sql),long.class);
	}

	public Map<String, Object> getById(String tableName,Object id){
		String sql="select * from "+tableName+" where id='"+id+"'";
		var rs = query(sql);
		if(rs==null||rs.size()==0){
			return new HashMap<>();
		}
		return rs.get(0);
	}

	protected List<Map<String, Object>> query(String sql) {
		try {
			return DbHelper.get(BigDataSource.getDefaultDataSource(), (conn) -> {
				return conn.executeList(sql, new Object[]{});
			});
		}catch (Exception e)
		{
			LogUtils.error(this.getClass(),Config.ProjectName,"query",e);
			throw e;
		}
	}

	protected Object query2(String sql) {
		try
		{
			return DbHelper.get(BigDataSource.getDefaultDataSource(),(conn)->{
				return conn.executeScalar(sql,new Object[]{});
			});
		}catch (Exception e)
		{
			LogUtils.error(this.getClass(),Config.ProjectName,"query2",e);
			throw e;
		}
	}
	public boolean executeUpdate(String sql) {
		try
		{
			DbHelper.call(BigDataSource.getDefaultDataSource(),(conn)->{
				conn.executeSql(sql,new Object[]{});
			});
		}catch (Exception e)
		{
			LogUtils.error(this.getClass(),Config.ProjectName,"executeUpdate",e);
			throw e;
		}
		return true;
	}

}
